Carry coarse label-source provenance into Under the Hood reports - #52
Conversation
|
Thank you for carrying coarse label-source provenance through the Under the Hood reporting path. This appears to address the reporting gap discussed in Issue #39. I would like to clarify one important point about the scope of this change. I have a real-world case where a post for which I voluntarily applied a content warning before publication appears in my Under the Hood report as This PR adds If account aggregation evaluates Could you please clarify:
The provenance added by this PR is valuable for transparency, but the most important practical question for affected users is whether responsible self-labeling can itself contribute to account-level visibility restrictions. |
|
@kiri234-code You are reading the scope correctly. This PR only changes the Under the Hood reporting path ( On the three questions, from the published dump:
One post labeled xAI owns whether self-labeling should be excluded from account restrictions. This PR does not claim to change that. |
|
@Pitchfork-and-Torch This confirms the distinction I wanted to understand: this PR affects only the Under the Hood reporting path, while the published account aggregation logic currently evaluates label types without checking their source. I also understand that the published code does not establish whether an author-applied warning is written as Your explanation of the default 3-in-5 aggregation window also clarifies why one This answers my questions about the scope of the PR and the behavior visible in the published code. I appreciate you taking the time to examine each point so carefully. |
Carry logical post IDs through the daily and backfill post-label rows, persist them in optional Thrift fields, aggregate the newest 1,000 distinct IDs per label into monthly rows, and emit them as strings in reportJson alongside postIdsComplete. IDs use the same logical-post identity (initialTweetId.getOrElse(tweetId)) as the existing carried counts, so an edited post chain stays one post in both the count and the ID list. Aggregation keeps the existing map-side combining: UthPostIds.merge is an associative, commutative reduce that sums carried and removed exactly as the previous sum did, and bounds the ID list at every merge. Peak reducer memory per key stays bounded rather than growing with posts per key, and the daily persisted rows carry the same bound as the monthly rows. Field IDs 4 and 11 are intentional, leaving 3 and 10 for the source-provenance fields proposed in xai-org#52.
TweetSafetyLabelEvent already has SafetyLabelSource (BotMaker vs Tool), but the daily job dropped it and the report had no field to show whether a label was applied manually. Persist a coarse category only — no rule_id or actor_ldap — and emit it on each post-label row. Fixes xai-org#39
7b6ca47 to
c65aa17
Compare
|
Parking this intern-stack PR per operator GitHub cleanup (2026-09-08). Hunt notes remain local. Not a reject of the class. |
Summary
Fixes #39.
README says Under the Hood should show whether labels were manually applied outside automated systems. The daily job already reads
TweetSafetyLabelEvent.labelbut kept only timestamps;SafetyLabelSourcewas dropped, and the serving types had no field to carry it.reportJson.sourceis one of four tokens:automated←BotMakerActionmanual←ToolActionllm← a Grok/LLM union member, detected byproductPrefixorgetNameplus the last non-empty./$segment (GrokAnnotation*), skipping a trailing synthetic$andgetSimpleName(can throw on Scala$names), so this compiles if that case is absent fromspam.rtfunknown← unset snapshot / tweet-flag / unmapped-source rows (serving clamp)Jobs persist only
automated|manual|llmafter trim/lowercase. Unmapped, missing, leftover tokens, and tweet-flag rows stay unset (source = Noneis set explicitly on flag writes). Daily counts clamp the last-apply source before grouping. When an event apply and an unset snapshot apply are merged, the later timestamp wins; a persistable event source is kept only if the later row is a snapshot gap-fill (isSnapshot), not a later unmapped event.latestAsOftreats the newest asOf as a full rewrite of(user, authored day, label): it keeps every persistable source from that asOf and drops older asOf rows so a later sourced rewrite cannot sit beside an earlier unset row. The month MH writer reconstructs rows with named Scrooge fields and pattern-matches leftover same-daycarried/removed(notbest._4/best._5). Serving clamps any other stored string tounknown, merges leftover rows that clamp to the same(label, source)by unioning days (larger carried/removed per day, then sum;groupBy.toListbeforeflatMapso Map.flatMap cannot drop rows), pattern-matches that leftover group key as(name, source)rather thant._1/t._2, and sorts that list by label then source soreportJsonorder is stable.postLabelSourceis a closed function (match + function closer beforeformatPercentage). Post-labelabout/effectlook up by the raw label id, same as the account path; displaynameis only written tolabel.Does not emit
rule_id,actor_ldap,agent_tool, or VF-client type names. Snapshot and tweet-flag inputs stay unset (no invented source).Based on current
xai-org/x-algorithmmain (c65aa179). Lane isunder-the-hood/only.Test plan
reportJsonpath.under-the-hood/has no published build/test target in this snapshot; no job was executed.source(ids 3 / 10) is backward-compatible with existing parquet/MH rows.reportJson.sourcecan only beautomated|manual|llm|unknown.unknownrow per label, including after daily count,latestAsOf, and reportJson day-union.(user, day, label)and does not emit both.automatedandmanualrows for one label both survivelatestAsOf.source = None.Automated/ padded tokens normalize to the allowlist instead ofunknown.(label, source).groupBykeys(name, source)by pattern match, nott._1/t._2.carried/removed, notbest._4/best._5.productPrefixorgetNameplus the last non-empty./$segment, notgetSimpleNameorString.split("$").postLabelSourcecloses beforeformatPercentage.postLabelAbout/postLabelEffectreceive the raw label id, not the display name.